package com.qf.websocket;

import com.qf.events.CommandEvent;
import com.qf.events.DeviceOnOffLineEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import sun.swing.plaf.synth.DefaultSynthStyle;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/*
杨威
2022/1/6
22:51
*/
public class MyBaseCommandHandler extends TextWebSocketHandler {
    @Autowired
    private ApplicationContext ac;
    //保存所有客户端的map
    private static Map<String, WebSocketSession> allClients=new HashMap<>();
    //记录心跳的map
    private static Map<String, Long> allClientLastHeartbeat = new HashMap<>();

    public static Map<String, WebSocketSession> getAllClients() {
        return allClients;
    }

    public static Map<String, Long> getAllClientLastHeartbeat() {
        return allClientLastHeartbeat;
    }

    @Override
    //连接成功我们就把会话保存起来
    //设备连接成功了 我们要发布一个时间 然后把设备的在线状态改为在线
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //把连接保存起来
        String uri = session.getUri().toString();//请求的地址
        //地址的最后一位是设备的标识
        String deviceId = uri.substring(uri.lastIndexOf("/") + 1);
        WebSocketSession currentSession = allClients.get(deviceId);
        if (currentSession != null) {
            currentSession.close();//设备多次连接的情况下,先关闭原先的连接,减少资源的占用
        }

        session.getAttributes().put("id", deviceId);//保存到会话中,方便下次使用,不用每次都裁减字符串
        allClients.put(deviceId, session);//将设备的链接保存起来
        System.err.println("设备" + deviceId + "连接成功");
        //保存最后一次心跳的时间
        allClientLastHeartbeat.put(deviceId,System.currentTimeMillis());
        //发布事件 更新状态为在线状态
        ac.publishEvent(new DeviceOnOffLineEvent(deviceId,new Date(),session.getRemoteAddress().getHostString(),1l));
        super.afterConnectionEstablished(session);//建立长连接
    }

    @Override
    //设备给我发消息 我就把消息记录下来 例如温度
    //有的设备会定时给服务器发送数据
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        super.handleTextMessage(session, message);//收到消息
        Object id = session.getAttributes().get("id");//设备的id
        //获取设备发过来的内容
        //发来什么内容无所谓 我们只需要记录时间 来判断设备是否存活
        String payload = message.getPayload();
        System.out.println("收到"+id+"发来的内容"+payload);
        //把心跳记录下来
        allClientLastHeartbeat.put((String) id,System.currentTimeMillis());
    }

    @Override
    //设备断开连接我们要发布一个事件 然后更新设备的在线状态为离线
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
//        super.afterConnectionClosed(session, status);
        //断开连接了 发布事件 更新为断线状态
        String id = (String) session.getAttributes().get("id");
        System.out.println(id+"断开连接了");
        ac.publishEvent(new DeviceOnOffLineEvent(id,new Date(),null,2l));
    }

    public void sendController(CommandEvent commandEvent){
        Object command = commandEvent.getCommand();
        String uid = commandEvent.getUid();
        //根据发过来的id获取到该设备的id
        WebSocketSession session = allClients.get(uid);
        if (session != null&&session.isOpen()) {
            //如果连接存在 则向设备发送命令
            try {
                session.sendMessage(new TextMessage(command.toString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void checkStatus(){
        CompletableFuture.runAsync(()->{
            HashMap<String,Long> hashMap=new HashMap();
            hashMap.putAll(allClientLastHeartbeat);
            hashMap.forEach((id,time)->{
                long currentTimeMillis = System.currentTimeMillis();
                if(currentTimeMillis-time>60000){
                    WebSocketSession webSocketSession = allClients.get(id);
                    if (webSocketSession != null&&webSocketSession.isOpen()) {
                        try {
                            webSocketSession.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                allClients.remove(id);
                allClientLastHeartbeat.remove(id);
            });
            hashMap.clear();
        });
    }

}
